package cn.bqjr.eily.samples.service.commom.impl;

import cn.bqjr.eily.redis.spring.boot.IRedisService;
import cn.bqjr.eily.samples.common.shiro.AuthLogAsync;
import cn.bqjr.eily.samples.common.shiro.KickoutUserAsync;
import cn.bqjr.eily.samples.dao.base.UserMapper;
import cn.bqjr.eily.samples.entity.po.User;
import cn.bqjr.eily.samples.entity.vo.LoginTokenVO;
import cn.bqjr.eily.samples.service.base.IUserService;
import cn.bqjr.eily.samples.service.commom.IAuthService;
import cn.bqjr.eily.samples.utils.ShiroUtils;
import cn.bqjr.eily.shiro.spring.boot.entity.ShiroProperties;
import cn.bqjr.eily.shiro.spring.boot.entity.TenantUserPwdToken;
import cn.bqjr.eily.utils.StringUtils;
import cn.bqjr.eily.web.exception.exclass.LoginException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.ShiroException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.awt.image.BufferedImage;
import java.util.Date;

@Service
public class AuthServiceImpl extends ServiceImpl<UserMapper, User> implements IAuthService {

    @Autowired
    private ShiroProperties shiroProperties;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private IUserService userService;

    @Autowired
    private AuthLogAsync authLogAsync;

    @Autowired
    private KickoutUserAsync userAsync;

    @Autowired
    private DefaultKaptcha kaptcha;

    private String getVerifyCacheKey(String key) {
        return shiroProperties.getBase().getVerifyCode().getValue() + ":" + key;
    }

    @Override
    public LoginTokenVO login(User loginUser) {
        String loginID = loginUser.getLoginId();
        String password = loginUser.getPassword();
        String companyId = loginUser.getCompanyId();
        TenantUserPwdToken token = new TenantUserPwdToken(loginID, password, companyId);
        Subject subject = SecurityUtils.getSubject();

        try {
            subject.login(token);
            if (subject.isAuthenticated()) {
                LoginTokenVO loginToken = new LoginTokenVO();
                loginToken.setTimestamp(new Date());
                loginToken.setToken(subject.getSession().getId().toString());

                Wrapper<User> wrapper = new EntityWrapper<User>().eq(User.LOGINID, loginID);
                if (StringUtils.isNotBlank(companyId)) {
                    wrapper = wrapper.eq(User.COMPANYID, companyId);
                }
                User user = userService.selectOne(wrapper);
                loginToken.setUserInfo(user);
                ShiroUtils.setLocalUser(user);

                userAsync.kickoutOtherSameUser();
                authLogAsync.insertLoginLog();
                return loginToken;
            }
            throw new LoginException();
        } catch (ShiroException e) {
            throw new LoginException(e.getMessage(), e);
        }
    }

    @Override
    public void logout() {
        ShiroUtils.logout();
    }

    @Override
    public BufferedImage getVerifycode(String verifyId) {
        String capText = kaptcha.createText();
        redisService.put(
                getVerifyCacheKey(verifyId),
                capText,
                shiroProperties.getBase().getVerifyCode().getExpireTime());
        return kaptcha.createImage(capText);
    }

    @Override
    public boolean checkVerifycode(String verifyId, String input) {
        String key = getVerifyCacheKey(verifyId);
        if (redisService.exist(key)) {
            return redisService.get(key, String.class).equalsIgnoreCase(input);
        }
        return false;
    }
}
